//////////////////////////////////////////////////////////////////////
// OctmapSampler.h
//
// SHEN Fangyang
// me@shenfy.com
//
// Copyright (C) SHEN Fangyang, 2011, All rights reserved.
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//  Brief Description
//
//	Octahedron map sampler, as in
//	[Engelhardt08] Octahedron Environment Maps, VMV08
//
//////////////////////////////////////////////////////////////////////
#pragma once

#include <IImgSampler.h>
#include <Logger.h>
#include <cmath>

#pragma comment (lib, W32LIB_BIN_FILE)

namespace grflib
{
	namespace image
	{
		//Class declaration

		///////////////////
		//Octmap Sampler 
		///////////////////
		template<typename T>
		class COctmapSampler :
			public IImgSampler<T>
		{
		public:
			COctmapSampler(void);
			virtual ~COctmapSampler(void);

			//texture access
			T texOctQuad(const float &x, const float &y, const float &z, const UINT &c);

			//conversion between 3D direction vector and 2D (u,v) coordinates
			static void Tex3DTo2DQuad(const float &x, const float &y, const float &z, /*input*/
									  float &u, float &v /*output*/);
			//static void Tex3DTo2DRect(const float &x, const float &y, const float &z, /*input*/
			//						  float &u, float &v /*output*/);
			static void Tex2DQuadTo3D(const float &u, const float &v, /*input*/
									  float &x, float &y, float &z /*output*/);

		protected:

		};

		//Class definition
		template<typename T>
		COctmapSampler<T>::COctmapSampler()
		{
		}

		template<typename T>
		COctmapSampler<T>::~COctmapSampler()
		{
		}

		template<typename T>
		void COctmapSampler<T>::Tex3DTo2DQuad(const float &x, const float &y, const float &z, /*input*/
											  float &u, float &v /*output*/)
		{
			//(px,py,pz)=p', (pqx, pqy, pqz)=p_q''
			float px, py, pz;
			float pqx, pqz;
			float sum;

			sum = abs(x) + abs(y) + abs(z);
			px = x / sum;
			py = y / sum;
			pz = z / sum;

			if (py < 0.0f) //projection and out-fold
			{
				pqx = math::Sign(px) * (1.0f - abs(pz));
				pqz = math::Sign(pz) * (1.0f - abs(px));
			}
			else //projection
			{
				pqx = px;
				pqz = pz;
			}

			u = (pqx + 1.0f) * 0.5f;
			v = 1.0f - ((pqz + 1.0f) * 0.5f);
		}

		template<typename T>
		void COctmapSampler<T>::Tex2DQuadTo3D(const float &u, const float &v, /*input*/
											  float &x, float &y, float &z /*output*/)
		{
			float absx, absz;

			x = u * 2.0f - 1.0f;
			z = (1.0f - v) * 2.0f - 1.0f;
			absx = abs(x);
			absz = abs(z);

			if (absx + absz > 1.0f) //y < 0, in-fold first
			{
				x = math::Sign(x) * (1.0f - absz);
				z = math::Sign(z) * (1.0f - absx);
				y = -(1.0f - abs(x) - abs(z)); //unproject
			}
			else		
				y = 1.0f - absx - absz; //unproject
			
			//normalize
			math::Normalize3D(x, y, z);
		}

		template<typename T>
		T COctmapSampler<T>::texOctQuad(const float &x, const float &y, const float &z, const UINT &c)
		{
			float u = 0.0f, v = 0.0f;

			//convert 3D direction vector to 2D (u,v)
			Tex3DTo2DQuad(x, y, z, u, v);
			
			//bilinear sampling
			T result = tex2D(u, v, c);
			return result;
		}
	}
}